/*
    Copyright (C) 2013 maik.jablonski@jease.org

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package jfix.util;

import java.io.File;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class I18N {

	private static ResourceBundle bundle;

	static {
		load(Locale.getDefault());
	}

	public static void load(Locale locale) {
		bundle = new MessageBundle("META-INF.i18n.msg", locale);
	}

	public static String get(String key) {
		if (key == null) {
			return null;
		}
		if (bundle.containsKey(key)) {
			return bundle.getString(key);
		} else {
			return key.replace("_", " ");
		}
	}

	static private class MessageBundle extends ResourceBundle {

		private String baseName;
		private String packageName;
		private Map<String, Object> messages;

		protected MessageBundle(String resource, Locale locale) {
			int idx = resource.lastIndexOf(".");
			this.baseName = resource.substring(idx + 1);
			this.packageName = resource.substring(0, idx);
			loadBundles(locale);
		}

		public Object handleGetObject(String key) {
			if (key == null) {
				throw new NullPointerException();
			}
			return messages.get(key);
		}

		public Enumeration<String> getKeys() {
			ResourceBundle parent = this.parent;
			return new ResourceBundleEnumeration(messages.keySet(),
					(parent != null) ? parent.getKeys() : null);
		}

		private void loadBundles(Locale locale) {
			messages = new HashMap<String, Object>();
			for (String bundleName : getBundleNames(baseName)) {
				ResourceBundle bundle = ResourceBundle.getBundle(bundleName,
						locale);
				Enumeration<String> keys = bundle.getKeys();
				while (keys.hasMoreElements()) {
					String key = keys.nextElement();
					messages.put(key, bundle.getObject(key));
				}
			}
		}

		private List<String> getBundleNames(String baseName) {
			List<String> bundleNames = new ArrayList<String>();
			try {
				String baseFileName = baseName + ".properties";
				String resourcePath = getResourcePath();
				String resourceName = resourcePath + baseFileName;
				Enumeration<URL> names = Thread.currentThread()
						.getContextClassLoader().getResources(resourceName);
				while (names.hasMoreElements()) {
					URL jarUrl = names.nextElement();
					String jarFile = URLDecoder.decode(jarUrl.getFile(),
							"UTF-8");
					if ("jar".equals(jarUrl.getProtocol())) {
						String filename = jarFile.substring(0, jarFile.length()
								- resourceName.length() - 2);
						if (filename.startsWith("file:")) {
							filename = filename.substring(5);
						}
						JarFile jar = new JarFile(filename);
						for (Enumeration<JarEntry> entries = jar.entries(); entries
								.hasMoreElements();) {
							JarEntry entry = entries.nextElement();
							String name = entry.getName();
							addMatch("", baseName, bundleNames, baseFileName,
									name);
						}
						jar.close();
					} else {
						File jarDirectory = new File(jarFile).getParentFile();
						if (jarDirectory.isDirectory()) {
							for (String name : jarDirectory.list()) {
								addMatch(resourcePath, baseName, bundleNames,
										baseFileName, name);
							}
						}
					}
				}
			} catch (Exception e) {
				throw new RuntimeException(e.getMessage(), e);
			}
			return bundleNames;
		}

		private String getResourcePath() {
			String result = "";
			if (packageName != null) {
				result = packageName.replaceAll("\\.", "/") + "/";
			}
			return result;
		}

		private void addMatch(String resourcePath, String baseName,
				List<String> bundleNames, String baseFileName, String name) {
			int prefixed = name.indexOf(baseName);
			if (prefixed > -1 && name.endsWith(baseFileName)) {
				String toAdd = resourcePath + name.substring(0, prefixed)
						+ baseName;
				if (!bundleNames.contains(toAdd)) {
					bundleNames.add(toAdd);
				}
			}
		}

		static private class ResourceBundleEnumeration implements
				Enumeration<String> {

			private Set<String> set;
			private Iterator<String> iterator;
			private Enumeration<String> enumeration;
			private String next = null;

			ResourceBundleEnumeration(Set<String> set,
					Enumeration<String> enumeration) {
				this.set = set;
				this.iterator = set.iterator();
				this.enumeration = enumeration;
			}

			public boolean hasMoreElements() {
				if (next == null) {
					if (iterator.hasNext()) {
						next = iterator.next();
					} else if (enumeration != null) {
						while (next == null && enumeration.hasMoreElements()) {
							next = enumeration.nextElement();
							if (set.contains(next)) {
								next = null;
							}
						}
					}
				}
				return next != null;
			}

			public String nextElement() {
				if (hasMoreElements()) {
					String result = next;
					next = null;
					return result;
				} else {
					throw new NoSuchElementException();
				}
			}
		}
	}

}
